
package primitives;

import java.util.*;

import org.nlogo.api.*;

/**
 * @author Daniel Graff Provides set functionalities. Proves if a given set is already contained as
 *         an element in an other set. Since permutations are not allowed it checks whether the
 *         given set is real combination.
 */
public class ContainsSetValidator
extends AbstractCustomReporter
{

    /**
     * Returns the syntax for NetLogo. The primitive takes two lists as input and returns a boolean
     * value.
     * 
     * @return Returns a list for input and output
     */
    @Override
    public Syntax getSyntax() {
        return Syntax.reporterSyntax(new int[] { Syntax.TYPE_LIST, Syntax.TYPE_LIST },
            Syntax.TYPE_BOOLEAN);
    }

    /**
     * Returns true if <code>list</code> contains a set element that contains the same elements as
     * <code>element</code>. It returns false if each set element in <code>
     * list</code> contains
     * different elements as <code>element</code>.
     * 
     * @param args
     *            The arguments
     * @param arg1
     *            The context
     * @return Returns true if a set element of <code>list</code> is equal to <code>
     * element</code>
     * @throws ExtensionException
     *             The exception
     * @throws LogoException
     */

    public Object report(Argument args[], Context arg1)
    throws ExtensionException, LogoException {

        logger.debug("Start Primitive ListTest...");

        @SuppressWarnings("unchecked")
        final List<Integer> element = args[0].getList();

        @SuppressWarnings("unchecked")
        final List<List<Integer>> list = args[1].getList();

        final HashSet<Integer> set = convertList2Set(element);
        final ArrayList<HashSet<Integer>> listOfSets = convertListOfLists2ListOfSets(list);

        if (listOfSets.contains(set))
            return true;

        return false;
    }

    /**
     * Converts a list to a set.
     * 
     * @param pList
     *            The list
     * @return Returns the set
     * @throws ExtensionException
     *             The exception
     */
    private HashSet<Integer> convertList2Set(final List<Integer> pList)
    throws ExtensionException {
        HashSet<Integer> set = new HashSet<Integer>();

        Iterator<Integer> it = pList.iterator();

        Object entry;
        while (it.hasNext()) {
            entry = it.next();

            if (!(entry instanceof Integer))
                throw new ExtensionException("Only supported for Integers!");
            set.add((Integer) entry);
        }

        return set;
    }

    /**
     * Converts a list of lists to a list of sets.
     * 
     * @param pList
     *            The list of lists
     * @return Returns the converted list
     * @throws ExtensionException
     *             The Exception
     */
    private ArrayList<HashSet<Integer>> convertListOfLists2ListOfSets(
        final List<List<Integer>> pList)
    throws ExtensionException {
        ArrayList<HashSet<Integer>> resultList = new ArrayList<HashSet<Integer>>();

        Iterator<List<Integer>> it = pList.iterator();

        List<Integer> entry;
        while (it.hasNext()) {
            entry = it.next();

            if (!(entry instanceof LogoList))
                throw new ExtensionException("Only supported for LogoLists!");
            resultList.add(convertList2Set(entry));
        }

        return resultList;
    }
}
